<?php

namespace Lib\Queue;


// 监控这个文件 每分钟执行一次

class QueueMonitor {

    CONST HANDLE_FILE_PATH = '/Lib/QueueHandle/%s.class.php'; //处理代码
    CONST BAK_FILE_PATH    = '/logs/queue/bak/%s.tmp';//备份文件路径
    CONST STOP_MSG         = 'stop_queue_%s';//停止信令
    const ACTION_PATH      = '/queueAction.php'; //执行文件入口
    const PHP_PATH         = '/usr/local/Cellar/php55/5.5.38/bin/php'; //php路径
    CONST BEAT_FILE_PATH   = '/logs/queue/beat/%s.beat';//心跳文件

    private $dieTime = 600; //10分钟不心跳就会重启进程

    /**
     * 监控队列
     */
    public function execute() {
        $queueConfList = \Lib\Conf::get("queue");

        foreach ($queueConfList as $k => $v) {
            // 检测报警
            $this->checkWarning($k, $v);

            // 检测文件是否有变化
            $actionName = $v['action'];

            /*
            $checkRs    = $this->checkHandleFile($actionName);
            if (false == $checkRs) {
                $stopCacheKey = sprintf(self::STOP_MSG, $actionName);
                Queue::sendStop($stopCacheKey);

                continue;
            }*/

            $isRunning = $this->checkRunning($actionName);
            if ($isRunning) {
                $checkBeat = $this->checkBeatsFile($actionName);
//                if (false == $checkBeat) {
                    $this->killProcess($actionName);
                    $this->performFile($actionName);
//                }
            } else {
                $this->performFile($actionName);
            }
        }
    }


    /**
     * 执行文件
     */
    public function performFile($actionName) {
        $actionPath = ROOT_PATH . self::ACTION_PATH;
        $cmd        = self::PHP_PATH . " {$actionPath} {$actionName} >/dev/null &";

        exec($cmd);
        exit;
        $pp = popen($cmd, 'r');
        @pclose($pp);

        return true;
    }


    /**
     * 检查进程
     */
    public function checkRunning($actionName) {
        $actionPath = ROOT_PATH . self::ACTION_PATH;
        $sourceCmd  = self::PHP_PATH . " {$actionPath} {$actionName}";

        $command = "ps -ef|grep '{$sourceCmd}'|grep -v 'grep'|awk '{print $2}'";
        exec($command, $res);

        return empty($res) ? false : $res;
    }

    /**
     * 杀进程
     */
    public function killProcess($actionName) {
        $actionPath = ROOT_PATH . self::ACTION_PATH;
        $sourceCmd  = self::PHP_PATH . " {$actionPath} {$actionName}";

        $command = "ps -ef|grep '{$sourceCmd}'|grep -v 'grep'|awk '{print $2}'";
        exec($command, $res);

        foreach ($res as $pid) {
            if (is_numeric($pid)) {
                $killCommand = "kill -9 {$pid}";
                exec($killCommand);
            }
        }

        return true;
    }

    /**
     * 检查处理文件
     */
    public function checkHandleFile($actionName) {
        $objectFileName = sprintf(ROOT_PATH . self::BAK_FILE_PATH, $actionName);
        $oldFileContent = file_get_contents($objectFileName);

        $newFileContent = $this->getHandleFileContent($actionName);
        $md5Content     = md5($newFileContent);
        if (empty($oldFileContent) || $oldFileContent != $md5Content) {
            $md5Content = md5($newFileContent);
            file_put_contents($objectFileName, $md5Content);

            return false;
        }

        return true;
    }

    /**
     * 获取处理队列程序内容
     */
    public function getHandleFileContent($actionName) {
        $filePath = sprintf(ROOT_PATH . self::HANDLE_FILE_PATH, $actionName);
        if (is_file($filePath)) {
            $fileContent = file_get_contents($filePath);
        }

        return $fileContent;
    }

    /**
     * 检查心跳文件
     */
    private function checkBeatsFile($actionName) {
        $file = sprintf(ROOT_PATH.self::BEAT_FILE_PATH, $actionName);

        $now = time();

        $last_beat_time = file_exists($file) ? (int)file_get_contents($file) : $now;

        if ($now - $last_beat_time > $this->dieTime) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 检测报是否报警
     *
     * @param string $queueKey
     * @param array $config 对应key的配置
     * @return bool
     */
    public function checkWarning($queueKey, $config) {
        $count = \Lib\Queue\Queue::count($queueKey);
        if ($count > $config['warning']) {
            echo '报警';
        }
    }

}